#pragma once
#include "Pascal.h"
#include "DebugUtils.h"
#include "data.h"
#include "pool.h"
#include "handletables.h"
#include "wc3_native_signature_parser.h"
#include "wc3observer.h"
#include "wc3string.h"
#include "wc3game.h"
#include "wc3_game_state.h"
#include "wc3jassvm.h"
//#include "debug_logger.h"
#ifdef JASS_VM_FAST_FLOAT
#include "fast_float.h"
#else
#include "wc3float.h"
#endif

#ifdef JASS_VM_FAST_FLOAT
typedef TFastFloatWar3 TJassFloat;
typedef PFastFloatWar3 PJassFloat;
#else
typedef TFloatWar3 TJassFloat;
typedef PFloatWar3 PJassFloat;
#endif

void myjassvm_initialization();
void myjassvm_finalization();

	typedef TDataTable<PScriptData> TVariablesTable;

	typedef TDataTable<PNativeFunc> TNativesDataTable;
	typedef TDataTable<PFuncAddr> TFunctionsDataTable;

	typedef TDataTable<PObserver> TVarChangeObserversTable;

	#ifndef TFrameData_H
	#define TFrameData_H
	class TFrameData
	{
	public:
		TVariablesTable Locals;
	public:
		TFrameData();
		procedure Clear();
		~TFrameData();
	};
	#endif

	//#ifndef TFrameData_2_H
	//#define TFrameData_2_H
	//class TThreadData_2;
	/*template <class TThreadData_2>
	class TThreads : public TFPGList<TThreadData_2>
	{
	public:
		TThreads();
	};*/

	class TNativeData
	{
	public:
		TScriptDataType* ArgumentsType;
	public:
		TNativeData(const TNativeFunc ANative);
		TNativeData();
	};

	typedef TDataTable<TNativeData> TNativeExtraDataTable;
	
	class TFramePoolManager
	{
	public:
		static PFrame CreateInstance(Pointer AParameter);
		static procedure ClearInstance(PFrame AInstance, Pointer AParameter);
		static procedure DestroyInstance(PFrame AInstance, Pointer AParameter);
	};

	#ifndef TFrameDataPoolManager_H
	#define TFrameDataPoolManager_H
	class TFrameData;
	class TFrameDataPoolManager
	{
	public:
		static TFrameData CreateInstance(Pointer AParameter);
		static procedure ClearInstance(TFrameData AInstance, Pointer AParameter);
		static procedure DestroyInstance(TFrameData AInstance, Pointer AParameter);
	};
	#endif

	class TScriptDataPoolManager
	{
	public:
		static PScriptData CreateInstance(Pointer AParameter);
		static procedure ClearInstance(PScriptData AInstance, Pointer AParameter);
		static procedure DestroyInstance(PScriptData AInstance, Pointer AParameter);
	};

	class TJassArrayPoolManager
	{
	public:
		static PJassArray CreateInstance(Pointer AParameter);
		static procedure ClearInstance(PJassArray AInstance, Pointer AParameter);
		static procedure DestroyInstance(PJassArray AInstance, Pointer AParameter);
	};
	//#endif

	#ifndef TProcessData_H
	#define TProcessData_H
	class TThreadData;
	//template <class TThreadData>
	class TThreads;
	class TProcessData
	{
	public:
		typedef TPool<PScriptData, TScriptDataPoolManager> TScriptDataPool;
		typedef TPool<PJassArray, TJassArrayPoolManager> TJassArrayPool;
		typedef TPool<PFrame, TFramePoolManager> TFramePool;
		typedef TPool<TFrameData, TFrameDataPoolManager> TFrameDataPool;
		typedef THandleTable<String> TMyStringStorage;
		typedef TThreads Threads_Type;
	public:
		Boolean operator== (const TProcessData &b);
		Boolean operator!= (const TProcessData &b);
	public:
		PInstance Instance;
		Threads_Type* Threads;
		TScriptDataPool ScriptDataPool;
		TJassArrayPool JassArrayPool;
		TFramePool FramePool;
		TFrameDataPool FrameDataPool;
		TNativesDataTable Natives;
		TNativeExtraDataTable NativesData;
		TFunctionsDataTable Functions;
		TVariablesTable Globals;
		TMyStringStorage MyStringStorage;
		TVarChangeObserversTable VarChangeObservers;
	public:
		TProcessData(PInstance AInstance);
		~TProcessData();
		TProcessData();
	};
	#endif

	#ifndef TProcesses_H
	#define TProcesses_H
	//template <class TProcessData>
	class TProcesses : public TFPGList<TProcessData>
	{
	public:
		TProcesses();
		~TProcesses();
	};
	#endif

	#ifndef TFrames_H
	#define TFrames_H
	//template <class TFrameData>
	class TFrames : public TFPGList<TFrameData>
	{
	public:
		TFrames();
		~TFrames();
	};
	#endif

	#ifndef TThreadData_H
	#define TThreadData_H
	class TThreadData
	{
	public:
		Boolean operator== (const TThreadData &b);
		Boolean operator!= (const TThreadData &b);
	public:
		TProcessData FProcess;
	public:
		TFrames Frames;
	public:
		procedure SetProcess(TProcessData* AProcess);
	public:
		//property Process: TProcessData read FProcess write SetProcess;
	public:
		procedure ClearFrames();
		TThreadData(TProcessData* AProcess);
		~TThreadData();
		TThreadData();
	};
	#endif

	//class TThreadData_2 : public TThreadData {};

	class TThreads : public TFPGList<TThreadData>
	{
	public:
		TThreads();
	};

	class TThreadTable : public THandleTable<Pointer> {};

	class TEnvironmentData
	{
	public:
		TProcesses* Processes;
		TThreadTable* ThreadTable;
	public:
		TEnvironmentData();
		~TEnvironmentData();
	};
	
procedure OnInstanceCreated(TInstanceHandle hInstance);
procedure OnInstanceDestroying(TInstanceHandle hInstance);
procedure OnInstanceInit(TInstanceHandle hInstance);
TScriptExitCode OnInstanceExecuteFunctionByName(TInstanceHandle hInstance, PChar Name, PDword ScriptResult);
TScriptExitCode OnInstanceExecuteFunctionByHandle(TInstanceHandle hInstance, Dword hFunction, PDword ScriptResult);
TJassStringHandle OnInstanceGetStringHandle(TInstanceHandle hInstance, PChar Value);
procedure OnEnableVarChangeEvent(PChar VariableName);

typedef Dword (*TTransformJassCodeHandleFunction) (TJassFunctionHandle hFunction);

procedure SetTransformJassCodeHandleFunction(TTransformJassCodeHandleFunction Callback);
TTransformJassCodeHandleFunction GetTransformJassCodeHandleFunction();
procedure ResetTransformJassCodeHandleFunction();
